package org.NooLab.structures;

 
 
import java.util.Observable;
import java.util.Observer;

 
import org.NooLab.itexx.comm.messages.CommBoxMessage;
import org.NooLab.itexx.comm.messages.CommBoxMessageIntf;
import org.NooLab.itexx.comm.tcp.box.TcpBox;
import org.NooLab.itexx.comm.tcp.box.infra.DataSenderIntf;
import org.NooLab.utilities.files.DFutils;
import org.NooLab.utilities.logging.PrintLog;




@SuppressWarnings("rawtypes")
public abstract class AppInstanceAbstract implements Runnable, AppInstanceControlIntf{

	
	public AppInstanceControlIntf instance;
	
	
	protected ArgumentsPublicIntf appArguments;
	protected InstanceProcessControlIntf processControl ;
	
	public String processName="" ;
	public String appSecret="";
	 
	
	public boolean resumeMode;
	public int glueMode;
	public int logLevel;
	public String projectname="";
	public String homedir="";
	public String contextMode="";
	public String onCompletion="";
	public String directsource="";
	public int    waitfor=-1;
	
	
	public AppCommBox commBox ;
	public boolean waitforReleaseConfirmed = false;
	
	
	
	private String appName; // e.g. "AstorSomApp"
	private String threadName;
	
	protected Thread instanceThrd;
	boolean stopping=false;
	
	public PrintLog out ;

	DFutils fileutil = new DFutils();


	
	// ========================================================================	
	public AppInstanceAbstract( String appname, String threadname){
		
		
		threadName = threadname;
		appName = appname;
		
		instanceThrd = new Thread(this, threadName);
	}
	// ========================================================================
	
	 

	@SuppressWarnings("rawtypes")
	public void setArguments(Object argumentsObj) {
		appArguments = (ArgumentsPublicIntf)argumentsObj;
	}

	
	public void waitfor(){
		WaitforStartupRelease wait;
		
		wait = new WaitforStartupRelease();
		if (wait.clearingOk==false){
			stopping=true;
			out.delay(500);
			System.exit(-8) ;
		}
	}
	

	@Override
	public void run() {
	
		if (resumeMode){
			
			try {
			
				resumeInstance();
	
			} catch (Exception e) {
				e.printStackTrace();
			}
			
		}else{
			prepareInstance();
		}
		
	
		
	}


	@Override
	public void close(int exitcode) {
		
		// 
		out.printErr(1, "shutting down application (x:"+exitcode+")");
		
		
		if (processControl!=null){
			processControl.interrupt(0);
		}else{
			out.print(3,"Nothing to stop, <processControl> was not up and running...");
		}
		
		
		
		out.delay(5000);
		System.exit(exitcode);
	}
	
	@Override
	public void issueUserbreak() {
		//  
		if (processControl!=null){
			processControl.interrupt(0);
		}else{
			System.err.println("Nothing to stop, <pontrol> was not up and running...");
		}
	}



	@Override
	public void confirmStartupCompletion(int code, String description) {
		//
		int r=-1;
		int clientport = 0;
		
		try {
			
			clientport = commBox.getInPort() ;
			DataSenderIntf sender = commBox.tcpBox.getTcpSender() ;
			
			r = (new CommBoxMessage(  
								  		CommBoxMessageIntf._MSG_ISSUER_APP)
							   		).issueTcpMessage( sender , clientport,
									   			  	   CommBoxMessageIntf._MSG_STARTUP_COMPLETION, 
									   			  	   processName, 
									   			  	   appSecret,0 );
			if (r<0){
				out.printErr(2, "Confirming the startup (code:"+code+") to iTexx using port <"+commBox.outPort+"> failed (err:"+r+").");
			}
		} catch (Exception e) {
			out.printErr(2, "potential problem met while trying to confirm the startup (code:"+code+") to iTexx:\n"+e.getMessage());
		}
	}

	
	public void clearStoppingFile(){
		
		boolean rB=true; 
		
		String filename ;
		
		try{

			
			filename = DFutils.createPath( homedir, "stop") ;
			
			rB = DFutils.fileExists(filename)==false ;

			if (rB==false){
				fileutil.deleteFile(filename) ;
			}
		}catch(Exception e){
			
		}
		
	
}

	
	abstract protected void prepareInstance();
	abstract protected void resumeInstance() throws Exception;
	
	
	protected TcpBox getTcpBox() {
		 
		return commBox.tcpBox;
	}
	
	public int prepareTcpBox( int oport, int iport) {
		int result=-1 ;
		int cport=-1;
		
		
		try{
			commBox = new AppCommBox( appName,iport, oport ) ;
			result = 0;
			cport = commBox.getInPort();
			
		}catch(Exception e){
			result = -7;
			String estr = e.getMessage();
			out.printErr(1, estr+"\nApplication will stop.\n");
			
			cport = appArguments.getInPort() ;
			(new CommBoxMessage(CommBoxMessageIntf._MSG_ISSUER_APP)).setOriginator("prepareTcpBox(<port"+iport+">) failed").issueConsoleMessage(CommBoxMessageIntf._MSG_STOPPING, processName, appSecret, cport );
			
			// (new CommBoxMessage()).issueTcpMessage( commBox.tcpBox.getTcpSender() , CommBoxMessageIntf._MSG_STOPPING, app.processName, app.secret) ;
			stopping=true;
			out.delay(500);
			System.exit(-9) ;
		}

		if (result>=0){
			out.delay(200) ;
			out.print(2, "Communication port has been started, listening on port <"+cport+"> ...");
		}
		return result;
	}
	// ----------------------------------------------------
	class WaitforStartupRelease implements Runnable{
	
		Thread wfsThrd;
		boolean isWaiting=false;
		boolean clearingOk = false;
		
		public WaitforStartupRelease(){
			wfsThrd = new Thread(this,"wfsThrd") ;
			wfsThrd.start();
			
			while (isWaiting==false){
				out.delay(1);
			}
			while (isWaiting){
				out.delay(100) ;
			}
		}
		
		
		@Override
		public void run() {
			
			int cport = 0;
			int z=0, zmax = 15000 ; 
			String itxMsg;
			
			zmax = 1200 ; // 3000 = 1min  TODO abc124 change value for production
			
			if (appSecret.length()>0){
				
				
				isWaiting = true;
				out.delay(5);
				// this will be confirmed through tcp, the message handler knows about 
				// the waitfor-secret ( for testing = "adkhf-23487asdf-3487sdfr-324")
				while ((z<zmax) &&(waitforReleaseConfirmed==false) && (stopping=false)){
					out.delay(20) ;
					z++;   // waiting max 5 minutes
				}
				
				if (waitforReleaseConfirmed==false){
					 
					out.printErr(1, "No clearance has been received while waiting, application will exit.\n"); 
					if (appArguments!=null){
						cport = appArguments.getInPort() ;
					}
					(new CommBoxMessage(CommBoxMessageIntf._MSG_ISSUER_APP)).issueConsoleMessage(CommBoxMessageIntf._MSG_STOPPING, processName, appSecret, cport);
					           // instance will be referenced as AppInstanceControlIntf
				}else{
					clearingOk = true;
				}
				isWaiting  = false; 
			}
		}
		
	} // inner class
}



